using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using WindowsGame.Data;
using WindowsGame.Enums;
using WindowsGame.Library;
using WindowsGame.Static;

namespace WindowsGame.GameObjects
{
	public class Sprite
	{
		private IList<Vector2> positions;
		private Int32 scale, block;
		private Int32 startPosX, startPosY;
		private Direction direction;
		private Int32 tailLength;
		private Int32 timeOnTile, timeAtTile;
		private Int32 tileToMove, tileAtMove;
		private Int32 noCols, noRows;
		private Random random;

		public Sprite(SnakeData data, GameSize size, Int32 noCols, Int32 noRows)
		{
			this.tailLength = data.TailLength;
			Int32 maxLength = 4 / (Int32)size * 10;
			if (tailLength < 0) { tailLength = 0; }
			if (tailLength > maxLength) { tailLength = maxLength; }

			this.noCols = noCols;
			this.noRows = noRows;
			InitializePositions(data);

			this.scale = (Int32)size;
			this.block = scale * 8;
			this.startPosX = data.StartPosX;
			this.startPosY = data.StartPosY;
			this.direction = data.Direction;
			
			this.timeOnTile = data.TimeOnTile;
			this.timeAtTile = timeOnTile;
			this.tileToMove = data.TileToMove;
			this.tileAtMove = 0;
			random = new Random();
		}

		public void Reset()
		{
			this.timeAtTile = timeOnTile;
			this.tileAtMove = 0;
		}

		public void Update(GameTime gameTime)
		{
			timeAtTile += gameTime.ElapsedGameTime.Milliseconds;
			if (timeAtTile < timeOnTile)
			{
				return;
			}

			// Reset clock and move.
			timeAtTile -= timeOnTile;

			// Check number times same direction.
			if (tileAtMove >= tileToMove)
			{
				tileAtMove = 0;
				direction = ChangeDirection(direction);
			}
			tileAtMove++;

			// Begin head.
			Vector2 velocity = Velocity.Data[direction];
			Vector2 oldHead = positions[0];
			Vector2 tmpHead = oldHead + velocity;

			// Move tail.
			for (int idx = this.tailLength; idx >= 1; --idx)
			{
				positions[idx] = positions[idx - 1];
			}

			// End head.
			tmpHead = CheckBoundariesWrap(tmpHead);
			positions[0] = tmpHead;
		}

		public void Draw()
		{
			Draw(0, Color.White);
			for (int idx = 1; idx <= this.tailLength; ++idx)
			{
				Draw(idx, Color.Red);
			}
		}

		private void InitializePositions(SnakeData data)
		{
			positions = new List<Vector2>();
			for (int idx = 0; idx <= this.tailLength; ++idx)
			{
				positions.Add(Vector2.Zero);
			}

			Vector2 tmpHead = new Vector2(data.StartPosX, data.StartPosY);
			tmpHead = CheckBoundariesStop(tmpHead);
			positions[0] = tmpHead;

			Vector2 offset = -1 * Velocity.Data[data.Direction];
			for (int idx = 1; idx <= this.tailLength; ++idx)
			{
				Vector2 tail = offset * idx;
				positions[idx] = tmpHead + tail;
			}
		}

		private void Draw(Int32 idx, Color color)
		{
			Engine.SpriteBatch.Draw(Assets.BlobTexture, positions[idx] * block, null, color, 0, Vector2.Zero, scale, SpriteEffects.None, 1);
		}

		private Vector2 CheckBoundariesStop(Vector2 tmpHead)
		{
			if (tmpHead.X < 0) { tmpHead.X = 0; }
			if (tmpHead.X > noCols - 1) { tmpHead.X = noCols - 1; }

			if (tmpHead.Y < 0) { tmpHead.Y = 0; }
			if (tmpHead.Y > noRows - 1) { tmpHead.Y = noRows -1; }

			return tmpHead;
		}
		private Vector2 CheckBoundariesWrap(Vector2 tmpHead)
		{
			if (tmpHead.X < 0) { tmpHead.X = noCols - 1; }
			if (tmpHead.X > noCols - 1) { tmpHead.X = 0; }

			if (tmpHead.Y < 0) { tmpHead.Y = noRows - 1; }
			if (tmpHead.Y > noRows - 1) { tmpHead.Y = 0; }

			return tmpHead;
		}

		private Direction ChangeDirection(Direction direction)
		{
			Int32 currDirection = (Int32)direction;
			Int32 nextDirection;
			while (true)
			{
				nextDirection = random.Next(4);
				if (currDirection == 0 && nextDirection != 1) { break; }
				if (currDirection == 1 && nextDirection != 0) { break; }
				if (currDirection == 2 && nextDirection != 3) { break; }
				if (currDirection == 3 && nextDirection != 2) { break; }
			}

			return (Direction)nextDirection;
		}
	}
}